/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* Local headers */
#include "ablibs.h"
#include "global.h"
#include "abimport.h"
#include "proto.h"

typedef unsigned char u_int8_t;
typedef unsigned short u_int16_t;
typedef unsigned int u_int32_t;
#define __BIT_TYPES_DEFINED__
#include <db.h>

#include "alarm_table.h"
#include "mentor.h"
#include "/proj4/api.h"

char	*db_name   = "/logs/alarms.db";
char	*log_file   = "/logs/daq_srv.log";
extern char *ep1_addr [5];
extern char *ep2_addr [5];

//-----------------------------------------------------------------------------
// открывает соединение с БД
//-----------------------------------------------------------------------------
static int open_db_connection (DB *dbp, const char *db)
{
	int ret;
	
	if ((ret = dbp->open(dbp, NULL, db, NULL, DB_RECNO, DB_CREATE, 0664)) != 0) {
		dbp->err(dbp, ret, "open %s", db);
		dbp->close (dbp, 0);
		dbp = NULL;
	}	

	return ret;
}

//-----------------------------------------------------------------------------
// закрывает соединение с БД
//-----------------------------------------------------------------------------
static int close_db_connection (DB *dbp)
{
	if (dbp)
		return dbp->close (dbp, 0);
	else 
		return -1;
}

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static int db_read_alarm (DBT *key, DBT *data, alarm_rec_t *alarm)
{
	char *dataptr;
	int ret = -1;
	size_t size;

	size  = sizeof (alarm->time);
	size += sizeof (alarm->front);
	size += sizeof (alarm->priority);
	size += sizeof (alarm->ack);
	size += 1;
	size += 1;
	
	if (key && data && alarm && (data->size >= size)) {
		alarm->recno = *(u_long*) key->data;
		dataptr = data->data;
		memcpy (&alarm->time, dataptr, sizeof (alarm->time));
		dataptr += sizeof (alarm->time);  
		memcpy (&alarm->front, dataptr, sizeof (alarm->front));
		dataptr += sizeof (alarm->front);  
		memcpy (&alarm->priority, dataptr, sizeof (alarm->priority));
		dataptr += sizeof (alarm->priority);  
		memcpy (&alarm->ack, dataptr, sizeof (alarm->ack));
		dataptr += sizeof (alarm->ack);  
		
		if (alarm->msg) free (alarm->msg);
		alarm->msg = strdup (dataptr);
		dataptr += strlen (alarm->msg)+ 1;
		if (alarm->comments) free (alarm->comments);
		alarm->comments = strdup (dataptr);
		
		ret = 0;
	}	
	return ret;
}

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static int db_alarm_count (DB *dbp)
{
	DB_BTREE_STAT *sp;
	int ret;
	
	if (dbp) {
		if ((ret = dbp->stat (dbp, NULL, &sp, DB_FAST_STAT))== 0) {
			ret = sp->bt_nkeys;
			free (sp);
			return ret;
		}
	}
	return 0;
}

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int read_alarms (PtWidget_t *list_wgt, int min_priority, int clear)
{
	DB *dbp;
	DBC *dbcp;
	DBT key, data;
	int ret;
	alarm_item_t *alarm_item;
	static int alarm_cnt;
	static int last_min_prio;
	
	/* Create the database handle */
	if ((ret = db_create (&dbp, NULL, 0)) != 0) {
		fprintf(stderr, "db_create: %s\n", db_strerror(ret));
		dbp = NULL;
	}
	open_db_connection (dbp, db_name);
	
	if ((db_alarm_count (dbp) > alarm_cnt)|| clear|| (min_priority != last_min_prio)) {
		alarm_cnt = db_alarm_count (dbp);
		last_min_prio = min_priority;
		PtGenListRemoveItems (list_wgt, NULL, NULL);
	
		/* Acquire a cursor for the database. */
		if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
			dbp->err(dbp, ret, "DB->cursor");
			return -1;
		}

		/* Re-initialize the key/data pair. */
		memset (&key, 0, sizeof (key));
		memset (&data, 0, sizeof (data));

		/* Walk through the database and print out the key/data pairs. */
		while ((ret = dbcp->c_get (dbcp, &key, &data, DB_NEXT)) == 0) {
			alarm_item = malloc (sizeof (alarm_item_t));
			memset (alarm_item, 0, sizeof (alarm_item_t));
			alarm_item->item.size.h = 18;
			db_read_alarm (&key, &data, &alarm_item->rec);
			if (alarm_item->rec.priority >= min_priority) {
				PtGenListAddItems (list_wgt, &alarm_item->item, NULL);
			} else {
				free (alarm_item);
			}
		}
		if (ret != DB_NOTFOUND)
			dbp->err(dbp, ret, "DBcursor->get");

		/* Close the cursor. */
		if ((ret = dbcp->c_close(dbcp)) != 0) {
			dbp->err(dbp, ret, "DBcursor->close");
			return (1);
		}
		PtSetResource (list_wgt, Pt_ARG_TOP_ITEM_POS, 1, 0);
	}	
	close_db_connection (dbp);

	return 0;
}

//-----------------------------------------------------------------------------
// выбор типа сообщений, которые показываются в списке
//-----------------------------------------------------------------------------
int alarm_combo_select (PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo)
{
	unsigned short *selected;

	/* eliminate 'unreferenced' warnings */
	widget = widget, apinfo = apinfo, cbinfo = cbinfo;

	PtGetResource (ABW_ComboAlarms, Pt_ARG_CBOX_SEL_ITEM, &selected, 0);
	read_alarms (ABW_AlarmsList, *selected, 1);	
	PtSetResource (ABW_AlarmComment, Pt_ARG_TEXT_STRING, NULL, 0);

	return (Pt_CONTINUE);
}

//-----------------------------------------------------------------------------
// прорисовка списка сообщений
//-----------------------------------------------------------------------------
void alarms_list_draw (PtWidget_t *widget, PtGenListItem_t *items, unsigned index,
        				unsigned nitems, PhRect_t *where)
{
	alarm_item_t *item;
	time_t time;
	char str [512], *strptr;
 	const int item_height = items->size.h;
    short bot;
    //PgColor_t fg, bg;
	
	PtGenListDrawBackground (widget, items, nitems, where, 0, 0, 0, 0 );

    do  {
        bot = where->ul.y + item_height;
		item = (alarm_item_t *)items;
        if (items->flags & Pt_LIST_ITEM_DAMAGED ) {
            where->lr.y = bot - 1;
			if (item) {
	            //PtGenListGetColors (widget, items, &fg, &bg );
				//switch (item->rec.priority) {
				//	case 1: fg = Pg_BLACK; 	break;
				//	case 2: fg = Pg_BLUE; 	break;
				//	case 3: fg = Pg_RED;	break;
				//	default: fg = Pg_BLACK;
				//}
            	//PgSetFillColor (bg);
	            //PgSetTextColor (fg);
    	        time = item->rec.time;
            
        	    strptr  = str;
				strptr += sprintf (strptr, "%u\t", item->rec.recno);
				strptr += strftime (strptr, 32, "%d-%m-%Y", localtime (&time)); 
				strptr += sprintf (strptr, "\t");
				strptr += strftime (strptr, 32, "%T", localtime (&time)); 
				strptr += sprintf (strptr, "\t");
				strptr += sprintf (strptr, "%c  ", item->rec.front? '+':'-');
				strptr += sprintf (strptr, "%s\t", item->rec.msg);

	            PtGenListDrawString (widget, items, str, where, 10, 0 );
			}
		}
        where->ul.y = bot;
        items = items->next;
	} while (--nitems);
}

//-----------------------------------------------------------------------------
// прорисовка соответствующих виджетов при выборе сообщения в списке
//-----------------------------------------------------------------------------
void alarms_list_select (PtWidget_t *widget, PtGenListItem_t *item, int pos, int column,
        					int nitems, int subtype, PhEvent_t *ev) 
{
	alarm_rec_t *rec = &((alarm_item_t *) item)->rec;
	
	if (rec) {
		PtSetResource (ABW_AlarmComment, Pt_ARG_TEXT_STRING, rec->comments, 0);
	}
}

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int load ( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo )
{
	unsigned short *selected;

	/* eliminate 'unreferenced' warnings */
	widget = widget, apinfo = apinfo, cbinfo = cbinfo;

	PtGetResource (ABW_ComboAlarms, Pt_ARG_CBOX_SEL_ITEM, &selected, 0);
	read_alarms (ABW_AlarmsList, *selected, 0);	

	return ( Pt_CONTINUE );
}

//-----------------------------------------------------------------------------
// Сопоставить выбранное сообщение с архивом
//-----------------------------------------------------------------------------
int alarm_show_arch ( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo )
{
	PtGenListItem_t *curitem;
	alarm_rec_t *rec;
	time_t t_win, t_end;

	/* eliminate 'unreferenced' warnings */
	link_instance = link_instance, apinfo = apinfo, cbinfo = cbinfo;
	
	curitem = PtGenListGetCurrent (ABW_AlarmsList);
	if (!curitem) return (Pt_END);

	rec = &((alarm_item_t *) curitem)->rec;
	PtSetResource (ABW_CwTrend_arch, TREND_ARG_TIME_PTR, &rec->time, sizeof (double));
		
	t_win = 60 * 25;
	PtSetResource (ABW_CwTrend_arch, TREND_ARG_TIME_WIN, t_win, 0);
	t_end = rec->time + t_win/2;
	PtSetResource (ABW_CwTrend_arch, TREND_ARG_TIME_END, t_end, 0);

	PtSetResource (ABW_CwTrend_arch, TREND_ARG_ADDR, 1, 0);
	PtSetResource (ABW_CwTrend_arch, TREND_ARG_HIST_NAME, ep1_addr, 5);
	PtSetResource (ABW_arch_opt_ep_combo, Pt_ARG_CBOX_SEL_ITEM, 1, 0);
	PtSetResource (ABW_CwTrend_arch, TREND_ARG_LOAD_DATA, 0, 0);

	return ( Pt_CONTINUE );
}

//-----------------------------------------------------------------------------
// Показать журнал системы
//-----------------------------------------------------------------------------
int
show_syslog( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo )
{
	FILE *fp;
	char buf [512];
	const char *pbuf [1] = {buf};

	/* eliminate 'unreferenced' warnings */
	link_instance = link_instance, apinfo = apinfo, cbinfo = cbinfo;

	fp = fopen (log_file, "r");

	PtListDeleteAllItems (ABW_syslog_list);
	if (fp) {
		while (fgets (buf, 512, fp)) {
			PtListAddItems (ABW_syslog_list, pbuf, 1, 1);		
		}
	}
	fclose (fp);
	PtListGotoPos (ABW_syslog_list, 1);

	return ( Pt_CONTINUE );
}


//-----------------------------------------------------------------------------
// Обновить журнал Mentor'a
//-----------------------------------------------------------------------------
int update_mentor_log ( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo)
{
	mem_data_t msg;
	unsigned short *trip_sel;
	unsigned short *drive_sel;
	int fd;
	int trip_code;
	int i;
	char buf [10];
	
	PtGetResource (ABW_trip_combo, Pt_ARG_CBOX_SEL_ITEM, &trip_sel, 0);
	PtGetResource (ABW_trip_drive_combo, Pt_ARG_CBOX_SEL_ITEM, &drive_sel, 0);

	memset (&msg, 0, sizeof (msg));

	switch (*trip_sel) {
		case 1: msg.addr = 1025; break;
		case 2: msg.addr = 1026; break;
		case 3: msg.addr = 1027; break;
		case 4: msg.addr = 1028; break;
	}
	
	switch (*drive_sel) {
		case 1: msg.node_id = 14; break;
		case 2: msg.node_id = 12; break;
		case 3: msg.node_id = 13; break;
		case 4: msg.node_id = 24; break;
		case 5: msg.node_id = 22; break;
		case 6: msg.node_id = 23; break;
		case 7: msg.node_id = 34; break;
		case 8: msg.node_id = 32; break;
		case 9: msg.node_id = 33; break;
	}
	
	fd = open ("/dev/ctansi", O_RDONLY);
	devctl (fd, DCMD_READ_PAR, &msg, sizeof (msg), NULL);
	close (fd);
	if (msg.ret_code < 0) {
		PtSetResource (ABW_trip_code, Pt_ARG_TEXT_STRING, NULL, 0);
		PtSetResource (ABW_trip_mnemonic, Pt_ARG_TEXT_STRING, NULL, 0);
		PtSetResource (ABW_trip_name, Pt_ARG_TEXT_STRING, "Нет связи с преобразователем", 0);
		PtSetResource (ABW_trip_comments, Pt_ARG_TEXT_STRING, "Проверьте, подано ли питание собственных нужд преобразователя", 0);
	}
	else {
		trip_code = msg.rdata;

		PtSetResource (ABW_trip_code, Pt_ARG_TEXT_STRING, NULL, 0);
		PtSetResource (ABW_trip_mnemonic, Pt_ARG_TEXT_STRING, NULL, 0);
		PtSetResource (ABW_trip_name, Pt_ARG_TEXT_STRING, NULL, 0);
		PtSetResource (ABW_trip_comments, Pt_ARG_TEXT_STRING, NULL, 0);
	
		for (i=0; i< (sizeof (mentor_trip)/ sizeof (*mentor_trip)); i++) {
			if (mentor_trip [i].code == trip_code) {
				PtSetResource (ABW_trip_code, Pt_ARG_TEXT_STRING, itoa (trip_code, buf, 10), 0);
				PtSetResource (ABW_trip_mnemonic, Pt_ARG_TEXT_STRING, mentor_trip [i].mnemonic, 0);
				PtSetResource (ABW_trip_name, Pt_ARG_TEXT_STRING, mentor_trip [i].name, 0);
				PtSetResource (ABW_trip_comments, Pt_ARG_TEXT_STRING, mentor_trip [i].comments, 0);			
			}	
		}
	}
		
	return ( Pt_CONTINUE );
}

//-----------------------------------------------------------------------------
// Показать журнал Mentor'a
//-----------------------------------------------------------------------------
int show_mentor_log( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo )
{
	const
	char *trip_name [] 	= {	"Последнее отключение (10.25)",
							"Отключение перед последним (10.26)",
							"Отключение перед 10.26 (10.27)",
							"Отключение перед 10.27 (10.28)" };
							
	const
	char *drive_name []	= {	"ШПТ-1 Master",
							"ШПТ-1 Slave",
							"ШПТ-1 Возбуждение",
							"ШПТ-2 Master",
							"ШПТ-2 Slave",
							"ШПТ-2 Возбуждение",
							"Р-ШПТ Master",
							"Р-ШПТ Slave",
							"Р-ШПТ Возбуждение" };

	/* eliminate 'unreferenced' warnings */
	link_instance = link_instance, apinfo = apinfo, cbinfo = cbinfo;

	PtListDeleteAllItems (ABW_trip_drive_combo);	
	PtListDeleteAllItems (ABW_trip_combo);	

	PtListAddItems (ABW_trip_drive_combo, drive_name, 9, 0);
	PtListAddItems (ABW_trip_combo, trip_name, 4, 0);

	PtSetResource (ABW_trip_drive_combo, Pt_ARG_CBOX_SEL_ITEM, 1, 0);
	PtSetResource (ABW_trip_combo, Pt_ARG_CBOX_SEL_ITEM, 1, 0);

	//update_mentor_log ( link_instance, apinfo, cbinfo );
	
	return ( Pt_CONTINUE );
}

//-----------------------------------------------------------------------------
// прорисовка списка активных аварий
//-----------------------------------------------------------------------------
void active_alarms_list_draw (PtWidget_t *widget, PtGenListItem_t *items, unsigned index,
        						unsigned nitems, PhRect_t *where) 
{
	alarm_item_t *item;
	//time_t time;
	char str [512], *strptr;
 	const int item_height = items->size.h;
    short bot;
    //PgColor_t fg, bg;

	int out = 0;
	ST_STATUS	status;
	PT_stCPOINT point;
	static IP_Msg *hmsg;
	static IP_Task *myself;	
	
	if (!myself) {
		if (!(myself = IP_TaskCreateMe (IP_GetChannelID(), "ph_view", NULL, NULL, 0))) {
	    	fprintf (stderr, "Could not initialize Cascade IPC subsystem\n");
		}
	}
	if (!hmsg) {
		hmsg = IP_MsgCreate (NULL, IP_MsgDefaultSize(), 0);
	}

	PtGenListDrawBackground (widget, items, nitems, where, 0, 0, 0, 0 );
    do  {
        bot = where->ul.y + item_height;
		item = (alarm_item_t *)items;
        if (items->flags & Pt_LIST_ITEM_DAMAGED ) {
            where->lr.y = bot - 1;
			if (item) {
	            //PtGenListGetColors (widget, items, &fg, &bg );

				//printf ("%s\n", item->rec.addr);
				memset (&point, 0, sizeof (point));
				point.name = item->rec.addr;
				if (myself) {
					if ((status = DH_ReadExistingPoint (myself, &point, hmsg, NULL)) == ST_OK) {
						out = point.value.i;
					} else {		
						fprintf (stderr, "Can't find point \"%s\" in datahub\n", point.name);
					}
				}

				//fg = Pg_BLACK;
	            //PgSetTextColor (fg);
    	        if ((out >> item->rec.bitnum) &1) {
					if (item->item.flags & Pt_LIST_ITEM_SELECTED) {
		            	//switch (item->rec.priority) {
		            	//	case 1: bg = Pg_VGA2; break;
	    	        	//	case 2: bg = Pg_VGA6; break;
	        	    	//	case 3: bg = Pg_VGA4; break;
	            		//}
	            		//PgSetFillColor (bg);
						//PgSetStrokeColor (Pg_BLACK);
						//PgDrawRect (where, Pg_DRAW_FILL_STROKE);
					} else {
		            	//switch (item->rec.priority) {
		            	//	case 1: bg = Pg_GREEN; break;
	    	        	//	case 2: bg = Pg_YELLOW; break;
	        	    	//	case 3: bg = Pg_RED; break;
	            		//}
	            		//PgSetFillColor (bg);
						//PgDrawRect (where, Pg_DRAW_FILL);					    	        		
					}
    	        }
    	        
            
        	    strptr  = str;
				strptr += sprintf (strptr, "%s", item->rec.msg);

	            PtGenListDrawString (widget, items, str, where, 10, 0 );
			}
		}
        where->ul.y = bot;
        items = items->next;
	} while (--nitems);
}

//-----------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------
void active_alarms_list_select (PtWidget_t *widget, PtGenListItem_t *item, int pos, int column,
						        int nitems, int subtype, PhEvent_t *ev) 
{
	alarm_rec_t *rec = &((alarm_item_t *) item)->rec;
	
	if (rec) {
		PtSetResource (ABW_ActiveAlarmComment, Pt_ARG_TEXT_STRING, rec->comments, 0);
	}
}

//-----------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------
int switch_to_alarm_list (PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo)
{
	PgColor_t *pcolor;
	
	/* eliminate 'unreferenced' warnings */
	widget = widget, apinfo = apinfo, cbinfo = cbinfo;

	PtGetResource (widget, Pt_ARG_FILL_COLOR, &pcolor, 0);	
	if (*pcolor != PgRGB (217, 217, 217)) {
		PtSetResource (ABW_PtPanelGroup1, Pt_ARG_PG_CURRENT_INDEX, 3, 0);
		PtSetResource (ABW_PtPanelGroup2, Pt_ARG_PG_CURRENT_INDEX, 1, 0);
	}

	return (Pt_CONTINUE);
}

